home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / player.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  18.7 KB  |  726 lines

  1. #include "player.h"        
  2.  
  3. //Player Shaders
  4. SHADER lighting, teamCol;
  5. D3DXHANDLE worldHandle, viewProjHandle, sunHandle, teamColHandle, vertexCol, mapSizeHandle;
  6. ID3DXLine *selLine = NULL;
  7. ID3DXSprite *menuSprite = NULL;
  8. IDirect3DTexture9* uiTexture = NULL;
  9. ID3DXFont *fontMoney = NULL;
  10.  
  11. extern D3DRECT SetRect(long x1, long y1, long x2, long y2);
  12.  
  13. void LoadPlayerResources(IDirect3DDevice9* m_pDevice)
  14. {
  15.     //Setup shaders
  16.     lighting.Init(m_pDevice, "shaders/lighting.vs", VERTEX_SHADER);
  17.     worldHandle = lighting.GetConstant("matW");
  18.     viewProjHandle = lighting.GetConstant("matVP");
  19.     sunHandle = lighting.GetConstant("DirToSun");
  20.     vertexCol = lighting.GetConstant("vertexCol");
  21.     mapSizeHandle = lighting.GetConstant("mapSize");
  22.  
  23.     teamCol.Init(m_pDevice, "shaders/teamCol.ps", PIXEL_SHADER);
  24.     teamColHandle = teamCol.GetConstant("tmCol");
  25.  
  26.     //Line for unit selection
  27.     D3DXCreateLine(m_pDevice, &selLine);
  28.  
  29.     D3DXCreateSprite(m_pDevice, &menuSprite);
  30.  
  31.     D3DXCreateTextureFromFile(m_pDevice, "textures/ui.dds", &uiTexture);
  32.  
  33.     D3DXCreateFont(m_pDevice, 20, 0, 0, 1, false,  
  34.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  35.                    DEFAULT_PITCH | FF_DONTCARE, "Arial Black", &fontMoney);
  36. }
  37.  
  38. void UnloadPlayerResources()
  39. {
  40.     if(selLine != NULL)
  41.         selLine->Release();
  42.     selLine = NULL;
  43.  
  44.     if(menuSprite != NULL)
  45.         menuSprite->Release();
  46.     menuSprite = NULL;
  47.  
  48.     if(uiTexture != NULL)
  49.         uiTexture->Release();
  50.     uiTexture = NULL;
  51. }
  52.  
  53. float GetCost(int type, bool m_isBuilding)
  54. {
  55.     if(m_isBuilding)
  56.     {
  57.         if(type == TOWNHALL)return 25.0f;
  58.         if(type == BARRACKS)return 20.0f;
  59.         if(type == TOWER)return 30.0f;
  60.     }
  61.     else
  62.     {
  63.         if(type == WORKER)return 7.0f;
  64.         if(type == SOLDIER)return 12.0f;
  65.         if(type == MAGICIAN)return 15.0f;
  66.     }
  67.  
  68.     return 100.0f;
  69. }
  70.  
  71. //////////////////////////////////////////////////////////////////////////////////
  72. //                                PLAYER                                            //
  73. //////////////////////////////////////////////////////////////////////////////////
  74.  
  75. PLAYER::PLAYER(int _teamNo, int _controller, D3DXVECTOR4 _teamCol, INTPOINT startPos, TERRAIN* _terrain, IDirect3DDevice9* _Device)
  76. {
  77.     m_teamNo = _teamNo;
  78.     m_teamColor = _teamCol;
  79.     m_pTerrain = _terrain;
  80.     m_pDevice = _Device;
  81.     m_areaSelect = m_placeBuilding = false;
  82.     m_nextUnitUpdate = 0.5f;
  83.     m_unitUpdateIndex = 0;
  84.     m_time = 0.0f;
  85.     m_controller = _controller;
  86.     m_pAi = NULL;
  87.     money = 0.0f;
  88.     unitLimit = 15;
  89.     m_teamStartLocation = startPos;
  90.     m_numKills = 0;
  91.  
  92.     if(m_pTerrain == NULL)return;
  93.  
  94.     //Add a few buildings
  95.     for(int i=0;i<0;i++)
  96.     {
  97.         INTPOINT p = FindClosestBuildingLocation(i, startPos);
  98.  
  99.         if(m_pTerrain->Within(p))
  100.             AddMapObject(i, p, true, true);
  101.     }
  102.  
  103.     //startPos = GetCenter();
  104.  
  105.     //Also add a few units
  106.     for(int i=0;i<1;i++)
  107.     {
  108.         INTPOINT mp;
  109.         bool ok = false;
  110.         do
  111.         {
  112.             mp.x = rand()%10 - 5 + startPos.x;
  113.             mp.y = rand()%10 - 5 + startPos.y;
  114.  
  115.             MAPTILE *tile = m_pTerrain->GetTile(mp);
  116.             if(tile != NULL)ok = tile->m_walkable && tile->m_pMapObject == NULL;
  117.         }
  118.         while(!ok);
  119.  
  120.         AddMapObject(i % 3, mp, false, true);
  121.     }
  122.  
  123.     if(m_controller == COMPUTER)
  124.     {
  125.         m_pAi = new MASTERAI(this, m_pTerrain);
  126.     }
  127. }
  128.  
  129. PLAYER::~PLAYER()
  130. {
  131.     if(m_pAi != NULL)
  132.         delete m_pAi;
  133.  
  134.     for(int i=0;i<m_mapObjects.size();i++)
  135.         if(m_mapObjects[i] != NULL)
  136.             delete m_mapObjects[i];
  137. }
  138.  
  139. MAPOBJECT* PLAYER::AddMapObject(int type, INTPOINT mp, bool m_isBuilding, bool finished)
  140. {
  141.     if(m_isBuilding)
  142.         m_mapObjects.push_back(new BUILDING(type, m_teamNo, finished, mp, m_pTerrain, this, true, m_pDevice));
  143.     else m_mapObjects.push_back(new UNIT(type, m_teamNo, mp, m_pTerrain, this, m_pDevice));
  144.  
  145.     return m_mapObjects[m_mapObjects.size() - 1];
  146. }
  147.  
  148. void PLAYER::RemoveMapObject(MAPOBJECT *mapObject)
  149. {
  150.     try
  151.     {
  152.         std::vector<MAPOBJECT*>::iterator i;
  153.         for(i=m_mapObjects.begin();i != m_mapObjects.end();i++)
  154.         {
  155.             if((*i) == mapObject)
  156.             {
  157.                 m_mapObjects.erase(i);
  158.                 break;
  159.             }
  160.         }
  161.     }
  162.     catch(...)
  163.     {
  164.         debug.Print("Error in PLAYER::RemoveMapObject()");
  165.     }
  166. }
  167.  
  168. void PLAYER::RenderMapObjects(CAMERA &camera)
  169. {
  170.     try
  171.     {
  172.         D3DXMATRIX identity;
  173.         D3DXMatrixIdentity(&identity);
  174.         
  175.         lighting.SetMatrix(viewProjHandle, camera.GetViewMatrix() * camera.GetProjectionMatrix());
  176.  
  177.         //Sun direction
  178.         D3DXVECTOR3 sun;
  179.         D3DXVec3Normalize(&sun, &D3DXVECTOR3(0.5f, 1.0f, -0.5));
  180.         lighting.SetVector3(sunHandle, sun);
  181.         lighting.SetVector3(mapSizeHandle, D3DXVECTOR3(m_pTerrain->m_size.x, m_pTerrain->m_size.y, 0.0f));
  182.  
  183.         //Team color
  184.         teamCol.SetVector4(teamColHandle, m_teamColor);
  185.         
  186.         //Fog-Of-War
  187.         m_pDevice->SetTexture(1, m_pTerrain->m_pFogOfWarTexture);
  188.  
  189.         //Vertex color
  190.         lighting.SetVector4(vertexCol, D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f));
  191.  
  192.         lighting.Begin();
  193.         teamCol.Begin();
  194.  
  195.         //Render units
  196.         for(int i=0;i<m_mapObjects.size();i++)
  197.             if(m_mapObjects[i] != NULL)
  198.                 if(!camera.Cull(m_mapObjects[i]->GetBoundingBox()))
  199.                 {
  200.                     if(m_mapObjects[i]->m_isBuilding)
  201.                         lighting.SetMatrix(worldHandle, m_mapObjects[i]->GetWorldMatrix());
  202.                     else lighting.SetMatrix(worldHandle, identity);
  203.  
  204.                     m_mapObjects[i]->Render();
  205.                 }
  206.  
  207.         teamCol.End();
  208.         lighting.End();
  209.  
  210.         //Render building fires
  211.         for(int i=0;i<m_mapObjects.size();i++)
  212.             if(m_mapObjects[i] != NULL && m_mapObjects[i]->m_isBuilding)
  213.             {
  214.                 BUILDING *build = (BUILDING*)m_mapObjects[i];
  215.                 build->RenderFires();
  216.             }
  217.     }
  218.     catch(...)
  219.     {
  220.         debug.Print("Error in PLAYER::RenderMapObjects()");
  221.     }
  222. }
  223.  
  224. void PLAYER::PaintSelectedMapObjects(CAMERA &camera)
  225. {
  226.     //Paint m_selected map objects
  227.     for(int i=0;i<m_mapObjects.size();i++)
  228.         if(m_mapObjects[i] != NULL)
  229.             if(!camera.Cull(m_mapObjects[i]->GetBoundingBox()))
  230.                 m_mapObjects[i]->PaintSelected(m_time * D3DX_PI * 2.0f);
  231. }
  232.  
  233. void PLAYER::UpdateMapObjects(float deltaTime)
  234. {
  235.     try
  236.     {
  237.         //Player time
  238.         m_time += deltaTime * 0.05f;
  239.         if(m_time > 1.0f)m_time -= 1.0f;
  240.         money += deltaTime;
  241.         if(money > 100.0f)money = 100.0f;
  242.  
  243.         //Update map objects
  244.         std::vector<MAPOBJECT*>::iterator i = m_mapObjects.begin();
  245.         while(i != m_mapObjects.end())
  246.         {
  247.             if((*i) == NULL || (*i)->isDead())
  248.             {
  249.                 if((*i) != NULL)delete (*i);
  250.                 m_mapObjects.erase(i);
  251.             }
  252.             else
  253.             {
  254.                 (*i)->Update(deltaTime);
  255.                 i++;
  256.             }
  257.         }
  258.  
  259.         //Call UnitAI() for each mapObject twice a second
  260.         m_nextUnitUpdate -= deltaTime;
  261.         if(m_nextUnitUpdate < 0.0f && !m_mapObjects.empty())
  262.         {
  263.             m_unitUpdateIndex++;
  264.             if(m_unitUpdateIndex >= m_mapObjects.size())
  265.                 m_unitUpdateIndex = 0;
  266.  
  267.             m_nextUnitUpdate = 0.5f / (float)m_mapObjects.size();
  268.             
  269.             if(!m_mapObjects[m_unitUpdateIndex]->m_isBuilding)
  270.             {
  271.                 UNIT *unit = (UNIT*)m_mapObjects[m_unitUpdateIndex];
  272.                 unit->UnitAI(false);
  273.             }
  274.         }
  275.  
  276.         //Master AI
  277.         if(m_controller == COMPUTER && m_pAi != NULL)
  278.             m_pAi->Update(deltaTime);
  279.     }
  280.     catch(...)
  281.     {
  282.         debug.Print("Error in PLAYER::UpdateMapObjects()");
  283.     }
  284. }
  285.  
  286. INTPOINT PLAYER::FindClosestBuildingLocation(int buildType, INTPOINT mp)
  287. {
  288.     try
  289.     {
  290.         //i = Search Radius
  291.         for(int i=0;i<30;i++)
  292.         {
  293.             for(int x=mp.x - i;x<=mp.x + i;x++)
  294.             {
  295.                 if(PlaceOk(buildType, INTPOINT(x, mp.y - i), m_pTerrain))return INTPOINT(x, mp.y - i);
  296.                 if(PlaceOk(buildType, INTPOINT(x, mp.y + i), m_pTerrain))return INTPOINT(x, mp.y + i);
  297.             }
  298.  
  299.             for(int y=mp.y - i;y<=mp.y + i;y++)
  300.             {
  301.                 if(PlaceOk(buildType, INTPOINT(mp.x - i, y), m_pTerrain))return INTPOINT(mp.x - i, y);
  302.                 if(PlaceOk(buildType, INTPOINT(mp.x + i, y), m_pTerrain))return INTPOINT(mp.x + i, y);
  303.             }
  304.         }
  305.     }
  306.     catch(...)
  307.     {
  308.         debug.Print("Error in PLAYER::FindClosestBuildingLocation()");
  309.     }
  310.  
  311.     //No good place found
  312.     return INTPOINT(-1, -1);
  313. }
  314.  
  315. void PLAYER::Select(MOUSE &mouse)
  316. {
  317.     try
  318.     {
  319.         if(mouse.ClickLeft())    // If the mouse button is pressed
  320.         {                
  321.             //If user pressed in the menu or minimap don't start the selection process
  322.             RECT minimap = {611, 9, 791, 189};
  323.             RECT UI = {650, 430, 800, 600};
  324.             if(mouse.inRect(minimap))return;
  325.             if(mouse.inRect(UI))return;
  326.  
  327.             for(int i=0;i<m_mapObjects.size();i++)    //Deselect all m_mapObjects
  328.                 m_mapObjects[i]->m_selected = false;
  329.  
  330.             if(!m_areaSelect)        // If no area selection is in progress
  331.             {    
  332.                 //Find closest m_mapObjects
  333.                 int mapObject = -1;
  334.                 float bestDist = 100000.0f;
  335.  
  336.                 D3DXMATRIX world;
  337.                 D3DXMatrixIdentity(&world);
  338.                 m_pDevice->SetTransform(D3DTS_WORLD, &world);
  339.                 RAY ray = mouse.GetRay();
  340.  
  341.                 for(int i=0;i<m_mapObjects.size();i++)
  342.                     if(m_mapObjects[i] != NULL && !m_mapObjects[i]->m_dead)
  343.                     {                    
  344.                         float dist = ray.Intersect(m_mapObjects[i]->GetBoundingBox());
  345.  
  346.                         if(dist >= 0.0f && dist < bestDist)
  347.                         {
  348.                             mapObject = i;
  349.                             bestDist = dist;
  350.                         }
  351.                     }
  352.  
  353.                 if(mapObject > -1)
  354.                     m_mapObjects[mapObject]->m_selected = true;
  355.                 else
  356.                 {
  357.                     m_areaSelect = true;        // if no unit if found,                                             
  358.                     m_startSel = mouse;        // start area selection
  359.                 }
  360.             }
  361.             else    //Area Selection in progress
  362.             {
  363.                 // Create area rectangle
  364.                 INTPOINT p1 = m_startSel, p2 = mouse;
  365.                 if(p1.x > p2.x){int temp = p2.x;p2.x = p1.x;p1.x = temp;}
  366.                 if(p1.y > p2.y){int temp = p2.y;p2.y = p1.y;p1.y = temp;}
  367.                 RECT selRect = {p1.x, p1.y, p2.x, p2.y};
  368.  
  369.                 //Draw selection rectangle
  370.                 D3DXVECTOR2 box[] = {D3DXVECTOR2(p1.x, p1.y), D3DXVECTOR2(p2.x, p1.y), 
  371.                                      D3DXVECTOR2(p2.x, p2.y), D3DXVECTOR2(p1.x, p2.y), 
  372.                                      D3DXVECTOR2(p1.x, p1.y)};
  373.  
  374.                 selLine->SetWidth(1.0f);
  375.                 selLine->Begin();
  376.                 selLine->Draw(box, 5, 0xffffffff);                
  377.                 selLine->End();
  378.  
  379.                 //Select any units inside our rectangle
  380.                 for(int i=0;i<m_mapObjects.size();i++)
  381.                     if(m_mapObjects[i] != NULL && !m_mapObjects[i]->m_isBuilding && !m_mapObjects[i]->m_dead)
  382.                     {
  383.                         INTPOINT p = GetScreenPos(m_mapObjects[i]->m_position, m_pDevice);
  384.                         if(p.inRect(selRect))m_mapObjects[i]->m_selected = true;
  385.                     }
  386.             }
  387.         }
  388.         else if(m_areaSelect)        //Stop area selection
  389.             m_areaSelect = false;
  390.  
  391.     }
  392.     catch(...)
  393.     {
  394.         debug.Print("Error in PLAYER::Select()");
  395.     }
  396. }
  397.  
  398. void PLAYER::UnitOrders(MOUSE &mouse, std::vector<PLAYER*> &players, CAMERA &camera)
  399. {
  400.     if(m_placeBuilding)return;
  401.  
  402.     RECT minimap = {611, 9, 791, 189};
  403.     RECT UI = {650, 430, 800, 600};
  404.  
  405.     if(mouse.ClickRight())
  406.     {
  407.         if(mouse.inRect(minimap))return;
  408.         if(mouse.inRect(UI))return;
  409.  
  410.         D3DXMATRIX identity;
  411.         D3DXMatrixIdentity(&identity);
  412.         m_pDevice->SetTransform(D3DTS_WORLD, &identity);
  413.         m_pDevice->SetTransform(D3DTS_VIEW, &camera.GetViewMatrix());
  414.         m_pDevice->SetTransform(D3DTS_PROJECTION, &camera.GetProjectionMatrix());
  415.  
  416.         RAY mRay = mouse.GetRay();
  417.         mouse.DisableInput(300);
  418.         
  419.         MAPOBJECT *enemyTarget = NULL;
  420.         float bestDist = 100000.0f;
  421.         
  422.         //See what enemy target the ray intersects
  423.         for(int p=0;p<players.size();p++)
  424.             if(players[p] != NULL && players[p]->m_teamNo != m_teamNo)
  425.                 for(int m=0;m<players[p]->m_mapObjects.size();m++)
  426.                     if(players[p]->m_mapObjects[m] != NULL)
  427.                     {
  428.                         float dist = mRay.Intersect(players[p]->m_mapObjects[m]->GetBoundingBox());
  429.     
  430.                         if(dist > 0.0f && dist < bestDist)
  431.                         {
  432.                             enemyTarget = players[p]->m_mapObjects[m];
  433.                             bestDist = dist;
  434.                         }
  435.                     }
  436.         
  437.         //Give orders
  438.         for(int i=0;i<m_mapObjects.size();i++)
  439.             if(m_mapObjects[i] != NULL)
  440.                 if(!m_mapObjects[i]->m_isBuilding && m_mapObjects[i]->m_selected)
  441.                 {
  442.                     //Cast to UNIT
  443.                     UNIT *unit = (UNIT*)m_mapObjects[i];
  444.  
  445.                     if(enemyTarget == NULL)
  446.                     {
  447.                         unit->Goto(mouse.m_mappos, false, true, STATE_MOVING);
  448.                     }
  449.                     else
  450.                     {
  451.                         unit->Attack(enemyTarget);
  452.                     }
  453.                 }
  454.     }
  455. }
  456.  
  457. BUILDING* PLAYER::GetAvailableBuilding(int type)
  458. {
  459.     for(int i=0;i<m_mapObjects.size();i++)
  460.         if(m_mapObjects[i] != NULL && m_mapObjects[i]->m_type == type && 
  461.            m_mapObjects[i]->m_isBuilding && !m_mapObjects[i]->m_dead)
  462.         {
  463.             BUILDING *building =  (BUILDING*)m_mapObjects[i];
  464.             if(building->m_buildProgress >= 1.0f && !building->m_training)
  465.                 return building;
  466.         }
  467.  
  468.     return NULL;
  469. }
  470.  
  471. UNIT* PLAYER::GetAvailableUnit(int type)
  472. {
  473.     for(int i=0;i<m_mapObjects.size();i++)
  474.         if(m_mapObjects[i] != NULL && m_mapObjects[i]->m_type == type &&
  475.            !m_mapObjects[i]->m_isBuilding && !m_mapObjects[i]->m_dead)
  476.         {
  477.             UNIT *unit =  (UNIT*)m_mapObjects[i];
  478.             if(unit->m_state == STATE_IDLE)
  479.                 return unit;
  480.         }
  481.  
  482.     return NULL;
  483. }
  484.  
  485. INTPOINT PLAYER::GetCenter()
  486. {
  487.     INTPOINT p;
  488.  
  489.     for(int i=0;i<m_mapObjects.size();i++)
  490.         if(m_mapObjects[i] != NULL)
  491.             p += m_mapObjects[i]->m_mappos;
  492.  
  493.     if(m_mapObjects.size() > 0)
  494.         p /= m_mapObjects.size();
  495.  
  496.     return p;
  497. }
  498.  
  499. RECT PLAYER::GetBaseArea()
  500. {
  501.     RECT r = {10000, 10000, -10000, -10000};
  502.     
  503.     for(int i=0;i<m_mapObjects.size();i++)
  504.         if(m_mapObjects[i] != NULL && m_mapObjects[i]->m_isBuilding)
  505.         {
  506.             RECT mr = m_mapObjects[i]->GetMapRect(5);
  507.  
  508.             if(mr.left < r.left)r.left = mr.left;
  509.             if(mr.right > r.right)r.right = mr.right;
  510.             if(mr.top < r.top)r.top = mr.top;
  511.             if(mr.bottom > r.bottom)r.bottom = mr.bottom;
  512.         }
  513.  
  514.     return r;
  515. }
  516.  
  517. void PLAYER::IsMapObjectsVisible()
  518. {
  519.     try
  520.     {
  521.         for(int i=0;i<m_mapObjects.size();i++)
  522.             if(m_mapObjects[i] != NULL)
  523.             {
  524.                 if(m_mapObjects[i]->m_isBuilding)
  525.                 {
  526.                     RECT r = m_mapObjects[i]->GetMapRect(0);
  527.                     m_mapObjects[i]->m_visible = false;
  528.  
  529.                     for(int y=r.top;y<=r.bottom && !m_mapObjects[i]->m_visible;y++)
  530.                         for(int x=r.left;x<=r.right && !m_mapObjects[i]->m_visible;x++)
  531.                             if(m_pTerrain->m_pVisitedTiles[x + y * m_pTerrain->m_size.x])
  532.                                 m_mapObjects[i]->m_visible = true;
  533.                 }
  534.                 else 
  535.                 {
  536.                     INTPOINT mp = m_mapObjects[i]->m_mappos;
  537.                     m_mapObjects[i]->m_visible = m_pTerrain->m_pVisibleTiles[mp.x + mp.y * m_pTerrain->m_size.x];
  538.                 }
  539.             }
  540.     }
  541.     catch(...)
  542.     {
  543.         debug.Print("Error in PLAYER::IsMapObjectsVisible()");
  544.     }
  545. }
  546.  
  547. bool MenuButton(int src, int dest, bool active, MOUSE &mouse)
  548. {
  549.     RECT srcRects[] = {{0, 0, 55, 70}, {0, 70, 55, 140}, {0, 140, 55, 210},
  550.                        {165, 0, 220, 70}, {165, 70, 220, 140}, {165, 140, 220, 210}};
  551.  
  552.     RECT destRects[] = {{665, 440, 715, 510}, {730, 440, 785, 510}, 
  553.                         {665, 520, 715, 590}, {730, 520, 785, 590}};
  554.  
  555.     bool over = mouse.Over(destRects[dest]);
  556.     bool press = false;
  557.  
  558.     if(!active)
  559.     {
  560.         srcRects[src].left += 110;
  561.         srcRects[src].right += 110;        
  562.     }
  563.     else
  564.     {
  565.         if(mouse.PressInRect(destRects[dest]))
  566.         {
  567.             mouse.DisableInput(300);
  568.             press = true;
  569.         }
  570.  
  571.         if(over){srcRects[src].left += 55;srcRects[src].right += 55;}
  572.     }
  573.  
  574.     menuSprite->Draw(uiTexture, &srcRects[src], NULL, &D3DXVECTOR3(destRects[dest].left, destRects[dest].top, 0.0f), 0xffffffff);
  575.  
  576.     return active && press;
  577. }
  578.  
  579. void PLAYER::Menu(MOUSE &mouse)
  580. {
  581.     if(m_placeBuilding)return;
  582.  
  583.     D3DRECT r = SetRect(660, 440, 790, 590);
  584.     m_pDevice->Clear(1, &r, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  585.  
  586.     RECT uiSrc = {0, 210, 150, 380};
  587.     RECT moneySrc = {150, 210, 400, 245};
  588.  
  589.     //find m_selected unit or building
  590.     MAPOBJECT *m_selected = NULL;
  591.     int numSelected = 0, numUnits = 0;
  592.     int numBuildings[] = {0, 0, 0};
  593.  
  594.     for(int i=0;i<m_mapObjects.size();i++)
  595.     {
  596.         if(m_mapObjects[i]->m_selected)
  597.         {
  598.             numSelected++;
  599.             m_selected = m_mapObjects[i];
  600.         }
  601.         
  602.         //Count buildings & units
  603.         if(!m_mapObjects[i]->m_dead)
  604.         {
  605.             if(m_mapObjects[i]->m_isBuilding)
  606.                 numBuildings[m_mapObjects[i]->m_type]++;
  607.             else numUnits++;
  608.         }
  609.     }
  610.  
  611.     //User interface menu...
  612.     menuSprite->Begin(D3DXSPRITE_ALPHABLEND);
  613.  
  614.     //Unit / Building menu
  615.     if(numSelected == 1)
  616.     {
  617.         if(m_selected->m_isBuilding)
  618.         {
  619.             BUILDING *building = (BUILDING*)m_selected;
  620.  
  621.             if(!building->m_training && building->m_buildProgress >= 1.0f)
  622.             {
  623.                 if(building->m_type == TOWNHALL)
  624.                     if(MenuButton(WORKER, 0, GetCost(WORKER, false) < money && numUnits < unitLimit, mouse))
  625.                         building->TrainUnit(WORKER);
  626.  
  627.                 if(building->m_type == BARRACKS)
  628.                     if(MenuButton(SOLDIER, 0, GetCost(SOLDIER, false) < money && numUnits < unitLimit, mouse))
  629.                         building->TrainUnit(SOLDIER);
  630.  
  631.                 if(building->m_type == TOWER)
  632.                     if(MenuButton(MAGICIAN, 0, GetCost(MAGICIAN, false) < money && numUnits < unitLimit, mouse))
  633.                         building->TrainUnit(MAGICIAN);
  634.             }
  635.         }
  636.         else
  637.         {
  638.             m_pSelectedUnit = (UNIT*)m_selected;
  639.  
  640.             if(m_pSelectedUnit->m_type == WORKER)
  641.             {
  642.                 if(MenuButton(TOWNHALL + 3, 0, GetCost(TOWNHALL, true) < money, mouse)){m_buildingToPlace = TOWNHALL; m_placeBuilding = true;}
  643.                 if(MenuButton(BARRACKS + 3, 1, numBuildings[0] > 0 && GetCost(BARRACKS, true) < money, mouse)){m_buildingToPlace = BARRACKS; m_placeBuilding = true;}
  644.                 if(MenuButton(TOWER + 3, 2, numBuildings[0] > 0 && numBuildings[1] > 0 && GetCost(TOWER, true) < money, mouse)){m_buildingToPlace = TOWER; m_placeBuilding = true;}
  645.             }
  646.         }        
  647.     }
  648.  
  649.     menuSprite->Draw(uiTexture, &uiSrc, NULL, &D3DXVECTOR3(650.0f, 430.0f, 0.0f), 0xffffffff);    
  650.  
  651.     //Draw player money counter
  652.     menuSprite->Draw(uiTexture, &moneySrc, NULL, &D3DXVECTOR3(10.0f, -2.0f, 0.0f), 0xffffffff);        
  653.  
  654.     char num[10];
  655.     itoa(money * 10, num, 10);
  656.     RECT rc[] = {{80, 2, 0, 0}, {162, 2, 0, 0}};
  657.     fontMoney->DrawText(NULL, num, -1, &rc[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  658.  
  659.     std::string u = itoa(numUnits, num, 10) + std::string(" / ") + itoa(unitLimit, num, 10);
  660.     fontMoney->DrawText(NULL, u.c_str(), -1, &rc[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  661.  
  662.     menuSprite->End();
  663. }
  664.  
  665. void PLAYER::PlaceBuilding(MOUSE &mouse, CAMERA &camera)
  666. {
  667.     if(!m_placeBuilding)return;
  668.  
  669.     //Create building to place...
  670.     BUILDING *building = new BUILDING(m_buildingToPlace, m_teamNo, true, mouse.m_mappos, m_pTerrain, this, false, m_pDevice);
  671.     building->m_visible = true;
  672.  
  673.     //Mouse input
  674.     if(mouse.ClickLeft())
  675.     {
  676.         mouse.DisableInput(300);
  677.  
  678.         if(PlaceOk(m_buildingToPlace, mouse.m_mappos, m_pTerrain))
  679.         {
  680.             m_pSelectedUnit->ConstructBuilding(m_buildingToPlace, mouse.m_mappos);
  681.             m_placeBuilding = false;
  682.         }
  683.     }
  684.     else if(mouse.ClickRight())
  685.     {
  686.         m_placeBuilding = false;
  687.         mouse.DisableInput(300);
  688.     }
  689.  
  690.     //Render building to place
  691.     lighting.SetMatrix(viewProjHandle, camera.GetViewMatrix() * camera.GetProjectionMatrix());
  692.  
  693.     D3DXVECTOR3 sun;
  694.     D3DXVec3Normalize(&sun, &D3DXVECTOR3(0.5f, 1.0f, -0.5));
  695.     lighting.SetVector3(sunHandle, sun);
  696.     teamCol.SetVector4(teamColHandle, m_teamColor);
  697.     
  698.     //Fog-Of-War
  699.     m_pDevice->SetTexture(1, m_pTerrain->m_pFogOfWarTexture);
  700.  
  701.     lighting.Begin();
  702.     teamCol.Begin();
  703.  
  704.     //Green if place ok, red otherwise
  705.     if(PlaceOk(m_buildingToPlace, mouse.m_mappos, m_pTerrain))
  706.         lighting.SetVector4(vertexCol, D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f));
  707.     else lighting.SetVector4(vertexCol, D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f));
  708.     lighting.SetMatrix(worldHandle, building->GetWorldMatrix());
  709.     building->Render();
  710.  
  711.     teamCol.End();
  712.     lighting.End();
  713.  
  714.     delete building;
  715. }
  716.  
  717. bool PLAYER::HasMapObject(int type, bool m_isBuilding)
  718. {
  719.     for(int i=0;i<m_mapObjects.size();i++)
  720.         if(m_mapObjects[i]->m_isBuilding == m_isBuilding)
  721.             if(m_mapObjects[i]->m_type == type)
  722.                 return true;
  723.  
  724.     return false;
  725. }
  726.